#include <common.h>
#include <privparent.h>
#include <privsock.h>
#include <tunable.h>

static void privop_pasv_get_data_sock(session_t *sess);
static void privop_pasv_active(session_t *sess);
static void privop_pasv_listen(session_t *sess);
static void privop_pasv_accept(session_t *sess);

void
minimize_privilege(void)
{
	//nobody进程负责权限处理
	//需要将父进程改为nobody进行来进行操作
	//目前这里都是以root权限进行启动的
	//nobody进程没有权限访问影子文件
	struct passwd *pw = getpwnam("nobody");
	if(NULL == pw) {
		return;
	}
	if(setegid(pw->pw_gid) < 0) {
		ERR_EXIT("setegid");
	}
	if(seteuid(pw->pw_uid) < 0) {
		ERR_EXIT("seteuid");
	}
	#if 0
	//只有在系统内核加载了capabilities模块后才支持这些权限操作
	struct __user_cap_header_struct cap_header;
	struct __user_cap_data_struct cap_data;
	memset(&cap_header,0,sizeof(cap_header));
	memset(&cap_data,0,sizeof(cap_data));
	//32位系统选择_LINUX_CAPABILITY_VERSION_1
	cap_header.version = _LINUX_CAPABILITY_VERSION_2;
	cap_header.pid = 0;
	__u32 cap_mask = 0;
	cap_mask |= (1 << CAP_NET_BIND_SERVICE);
	cap_data.effective = cap_mask;
	cap_data.permitted = cap_mask;
	cap_data.inheritable = 0;
	if(capset(&cap_header,&cap_data) < 0) {
		perror("capset");
	}
	#endif
	//需要安装libcap库来进行支持
	cap_value_t cap_value;
	cap_t adopt_caps = cap_init();
	cap_value = CAP_NET_BIND_SERVICE;
	cap_set_flag(adopt_caps,CAP_EFFECTIVE,1,&cap_value,CAP_SET);
	cap_set_flag(adopt_caps,CAP_PERMITTED,1,&cap_value,CAP_SET);
	if(cap_set_proc(adopt_caps) < 0) {
		ERR_EXIT("cap_set_proc");
	}
	cap_free(adopt_caps);
}

void
ftp_nobody_process(session_t *sess)
{
	char cmd;
	//获取权限
	minimize_privilege();
	while(1) {
		//read(sess->parent_fd,&cmd,1);
		//解析处理内部命令
		cmd = priv_sock_get_cmd(sess->parent_fd);
		switch(cmd)
		{
		case PRIV_SOCK_GET_DATA_SOCK :
			privop_pasv_get_data_sock(sess);
			break;
		case PRIV_SOCK_PASV_ACTIVE :
			privop_pasv_active(sess);
			break;
		case PRIV_SOCK_PASV_LISTEN :
			privop_pasv_listen(sess);
			break;
		case PRIV_SOCK_PASV_ACCEPT :
			privop_pasv_accept(sess);
			break;
		default :
			break;
		}
	}
}

static void privop_pasv_get_data_sock(session_t *sess)
{
	/*
	nobody进程接收PRIV_SOCK_GET_DATA_SOCK命令
	进一步接收一个整数 也就是端口号 
	接收一个字符串 也就是ip

	socket
	bind(20)
	connect(ip,port)

	成功应答OK
		需要把连接好的套接字发送给服务进程send_fd
		服务进程要使用recv_fd
	失败应答BAD
	*/
	uint16_t port = (uint16_t)priv_sock_get_int(sess->parent_fd);
	char ip[16] = {0};
	priv_sock_recv_buf(sess->parent_fd,ip,sizeof(ip));

	int sockfd = tcp_client(20);
	if(sockfd < 0) {
		priv_sock_send_result(sess->parent_fd,PRIV_SOCK_RESULT_BAD);
		return;
	}
	struct sockaddr_in port_addr;
	socklen_t addrlen = sizeof(struct sockaddr_in);
	memset(&port_addr,0,addrlen);
	port_addr.sin_family = AF_INET;
	port_addr.sin_port = htons(port);
	//port_addr.sin_addr = inet_addr(ip);
	inet_aton(ip,&(port_addr.sin_addr));
	if(connect_timeout(sockfd,(struct sockaddr *)&port_addr,
					addrlen,tunable_connect_timeout) < 0) {
		perror("connect_timeout");
		close(sockfd);
		priv_sock_send_result(sess->parent_fd,PRIV_SOCK_RESULT_BAD);
		return;
	}
	//成功了
	priv_sock_send_result(sess->parent_fd,PRIV_SOCK_RESULT_OK);
	priv_sock_send_fd(sess->parent_fd,sockfd);
	close(sockfd);
}
static void privop_pasv_active(session_t *sess)
{
	int active;
	if(sess->pasv_listen_fd != -1) {
		active = 1;
	} else {
		active = 0;
	}
	priv_sock_send_int(sess->parent_fd,active);
}
static void privop_pasv_listen(session_t *sess)
{
	//
	sess->pasv_listen_fd = tcp_server_sock_init(NULL,0);
	//确定绑定的端口情况
	struct sockaddr_in addr;
	socklen_t addrlen = sizeof(addr);
	if(getsockname(sess->pasv_listen_fd,
		(struct sockaddr *)&addr,&addrlen) < 0) {
		ERR_EXIT("getsockname");
	}
	uint16_t port = ntohs(addr.sin_port);
	priv_sock_send_int(sess->parent_fd,port);
}
static void privop_pasv_accept(session_t *sess)
{
	int connfd = accept_timeout(sess->pasv_listen_fd,NULL,NULL,tunable_accept_timeout);
	if(connfd < 0) {
		priv_sock_send_result(sess->parent_fd,PRIV_SOCK_RESULT_BAD);
		return;
	}
	close(sess->pasv_listen_fd);
	sess->pasv_listen_fd = -1;
	priv_sock_send_result(sess->parent_fd,PRIV_SOCK_RESULT_OK);
	priv_sock_send_fd(sess->parent_fd,connfd);
	close(connfd);
}

